from datetime import datetime, timedelta
from flask import Blueprint, request, current_app
from util.permission import permission_required
from util.result import Result
from models import db, BorrowRecord, Book, Reader

# 创建借阅记录管理蓝图
api_bp = Blueprint('borrow', __name__)


# 1. 创建借阅记录（办理借书，需 borrow:create 权限）
@api_bp.route('/borrow', methods=['POST'])
@permission_required('borrow:create')  # 权限标识与业务匹配
def create_borrow():
    try:
        data = request.get_json()
        if not data:
            return Result.error("请输入借阅信息")

        # 借阅记录必填字段
        required_fields = ['borrow_no', 'book_id', 'reader_id', 'days']
        for field in required_fields:
            if field not in data or not str(data[field]).strip():
                return Result.error(f"{field}是必填项")

        # 1. 提取并验证核心参数
        borrow_no = str(data['borrow_no']).strip()  # 借阅编号（用户输入）
        book_id = data['book_id']  # 图书ID（关联 books 表）
        reader_id = data['reader_id']  # 读者ID（关联 readers 表）
        days = data['days']  # 借阅天数（计算应还日期）

        # 验证借阅编号唯一性
        if BorrowRecord.query.filter_by(borrow_no=borrow_no).first():
            return Result.error(f"借阅编号'{borrow_no}'已存在")

        # 2. 校验图书状态（是否存在+是否可借）
        book = Book.query.get(book_id)
        if not book:
            return Result.error(f"图书不存在")
        if not book.is_borrowable():  # 调用 Book 模型的核心方法判断可借性
            return Result.error(f"图书《{book.name}》当前已被借出，无法重复借阅")

        # 3. 校验读者状态（是否存在+是否有逾期未还）
        reader = Reader.query.get(reader_id)
        if not reader:
            return Result.error(f"读者不存在")
        if reader.has_overdue_books():  # 调用 Reader 模型的核心方法判断逾期
            return Result.error(f"读者{reader.name}存在逾期未还图书，无法新借")

        # 4. 计算应还日期（借阅日 + 借阅天数）
        borrow_date = datetime.now()
        due_date = borrow_date + timedelta(days=days)

        # 5. 创建借阅记录（状态默认0-借阅中）
        new_borrow = BorrowRecord(
            borrow_no=borrow_no,  # 使用用户输入的借阅编号
            book_id=book_id,
            reader_id=reader_id,
            borrow_date=borrow_date,
            due_date=due_date,
            status=0,  # 0=借阅中，1=已归还，2=已逾期
            created_at=datetime.now(),
            updated_at=datetime.now()
        )

        db.session.add(new_borrow)
        db.session.commit()

        return Result.success("借阅成功")

    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"创建借阅记录异常: {str(e)}")
        return Result.error("办理借书失败，请稍后重试")


# 2. 分页查询借阅记录（需 borrow:read 权限，支持多维度筛选）
@api_bp.route('/borrow', methods=['GET'])
@permission_required('borrow:read')
def search_borrow():
    try:
        # 1. 分页参数（默认第1页，每页10条，限制最大100条）
        page = request.args.get('page', 1, type=int)
        size = request.args.get('size', 10, type=int)
        page = 1 if page < 1 else page
        size = 10 if size < 1 or size > 100 else size

        # 2. 多维度筛选参数（贴合借阅业务场景）
        kw = request.args.get('kw', '').strip()  # 模糊搜索（图书名/读者名/借阅编号）
        status = request.args.get('status',type=str)  # 状态筛选（all/0/1/2）
        begin = request.args.get('begin', type=str)  # 借阅开始日期（如2024-01-01）
        end = request.args.get('end', type=str)  # 借阅结束日期（如2024-01-31）

        # 3. 构建查询（关联图书和读者表，支持多表筛选）
        query = db.session.query(
            BorrowRecord,
            Book.name.label('book_name'),  # 图书名
            Reader.name.label('reader_name')  # 读者名
        ).join(
            Book, BorrowRecord.book_id == Book.id, isouter=True  # 左关联图书表
        ).join(
            Reader, BorrowRecord.reader_id == Reader.id, isouter=True  # 左关联读者表
        )

        # 4. 应用筛选条件
        if kw:
            query = query.filter(
                (BorrowRecord.borrow_no.like(f"%{kw}%")) |
                (Book.name.like(f"%{kw}%")) |
                (Reader.name.like(f"%{kw}%"))
            )
        # 状态筛选（0=借阅中，1=已归还，2=已逾期）
        if status and status != 'all':
            query = query.filter(BorrowRecord.status == status)
        # 借阅日期范围筛选
        if begin:
            begin = datetime.strptime(begin, '%Y-%m-%d')
            query = query.filter(BorrowRecord.borrow_date >= begin)
        if end:
            end = datetime.strptime(end, '%Y-%m-%d')
            # 结束日期加1天，避免遗漏当日数据（如2024-01-31包含全天）
            end = end + timedelta(days=1)
            query = query.filter(BorrowRecord.borrow_date < end)

        # 5. 排序（默认按借阅编号排序）
        query = query.order_by(BorrowRecord.borrow_date.desc())

        # 6. 执行分页查询
        paginated_result = query.paginate(page=page, per_page=size, error_out=False)
        records = paginated_result.items

        # 7. 格式化返回数据（包含关联表信息和状态文字）
        result_list = []
        for borrow, book_name, reader_name in records:
            result_list.append({
                "id": borrow.id,
                "borrow_no": borrow.borrow_no,
                "book_id": borrow.book_id,
                "book_name": book_name,
                "reader_id": borrow.reader_id,
                "reader_name": reader_name,
                "borrow_date": borrow.borrow_date.strftime("%Y-%m-%d %H:%M:%S") if borrow.borrow_date else None,
                "due_date": borrow.due_date.strftime("%Y-%m-%d %H:%M:%S") if borrow.due_date else None,
                "return_date": borrow.return_date.strftime("%Y-%m-%d %H:%M:%S") if borrow.return_date else None,
                "status": borrow.get_status_text(),
                "created_at": borrow.created_at.strftime("%Y-%m-%d %H:%M:%S"),
                "updated_at": borrow.updated_at.strftime("%Y-%m-%d %H:%M:%S")
            })

        # 8. 构建分页响应体（包含分页元信息，方便前端渲染分页组件）
        page_data = {
            "total": paginated_result.total,  # 总记录数
            "page": page,  # 当前页码
            "size": size,  # 每页条数
            "pages": paginated_result.pages,  # 总页数
            "list": result_list
        }

        return Result.success("借阅记录查询成功", data=page_data)

    except Exception as e:
        current_app.logger.error(f"分页查询借阅记录异常: {str(e)}")
        return Result.error("查询借阅记录失败，请稍后重试")


# 3. 修改借阅记录 支持还书和续借（需 borrow:update 权限）
@api_bp.route('/borrow', methods=['PUT'])
@permission_required('borrow:update')
def update_borrow():
    try:
        # 获取操作类型参数
        operation = request.json.get('operation') # 0 还书 1 续借
        id = request.json.get('id')
        # 查询借阅记录
        borrow_record = BorrowRecord.query.get(id)
        if not borrow_record:
            return Result.error("借阅记录不存在")

        # 1. 处理还书逻辑
        if operation == 0:
            # 校验状态（仅“借阅中”可办理还书）
            if borrow_record.status != 0:
                status_text = borrow_record.get_status_text()
                return Result.error(f"当前记录状态为【{status_text}】，仅“借阅中”可办理还书")

            # 调用模型方法处理还书
            borrow_record.handle_return()
            return Result.success("图书归还成功")

        # 2. 处理续借逻辑
        elif operation == 1:
            # 校验状态（仅“借阅中”可续借）
            if borrow_record.status != 0:
                status_text = borrow_record.get_status_text()
                return Result.error(f"当前记录状态为【{status_text}】，仅“借阅中”可办理续借")

            # 获取续借天数，默认30天
            days = request.json.get('days', 30)
            if not isinstance(days, int) or days <= 0 or days > 60:
                return Result.error("续借天数必须为1-60之间的整数")

            # 调用模型方法处理续借
            new_due_date=borrow_record.handle_renewal(days)
            return Result.success(f"图书续借成功,应还日期为{new_due_date}")

    except ValueError as ve:
        current_app.logger.error(f"借阅操作业务异常: {str(ve)}")
        return Result.error(str(ve))
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"借阅操作系统异常: {str(e)}")
        return Result.error("操作失败，请稍后重试")


# 4. 删除借阅记录（需 borrow:delete 权限，仅允许删除“已归还”记录）
@api_bp.route('/borrow/<int:record_id>', methods=['DELETE'])
@permission_required('borrow:delete')
def delete_borrow(record_id):
    try:
        # 1. 查询借阅记录
        borrow_record = BorrowRecord.query.get(record_id)
        if not borrow_record:
            return Result.error(f"借阅记录不存在")

        # 2. 业务约束：仅“已归还”记录可删除（避免误删有效借阅数据）
        if borrow_record.status != 1:
            return Result.error("仅已归还的借阅记录可删除")

        # 3. 删除记录
        db.session.delete(borrow_record)
        db.session.commit()

        return Result.success(f"借阅记录删除成功")

    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"删除借阅记录异常: {str(e)}")
        return Result.error("删除借阅记录失败，请稍后重试")
